﻿using Autofac;
using MgSoft.Log;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading;

namespace MgSoft.Import.Exchange
{
    public abstract class ExchangeTaskManager<TDto, TTask, TDao> : ITaskManager, IExchangeTaskManager
        where TDto : class,IExchangeDto
        where TTask : IExchangeTask
        where TDao : IExchangeDao
    {

        /// <summary>
        /// 线程池最大线程数
        /// </summary>
        protected virtual int MaxThreaderCount { get; } = 40;
        /// <summary>
        /// 启用线程池
        /// </summary>
        protected virtual bool useThreadPoolFlag { get; } = true;
        protected static AutoResetEvent threadEndEvent = new AutoResetEvent(false);
        protected int do_totalThreadNumber = 0;

        protected readonly ILifetimeScope lifetimeScope;
        /// <summary>
        /// 实现ExcelTaskManager的类型名称，用于名称注入
        /// </summary>
        public string Name => this.GetType().FullName;

        public abstract string Title { get; }

        public abstract string Describe { get; }
        protected TDao exchangeDao { get; }
        protected TTask exchangeTask { get; }

        protected IMgLog log { get; private set; } = new NullMgLog();

        public ExchangeTaskManager(ILifetimeScope lifetimeScope)
        {
            this.lifetimeScope = lifetimeScope;
            IMgLogger mgLogger;
            lifetimeScope.TryResolve<IMgLogger>(out mgLogger);
            exchangeDao = lifetimeScope.Resolve<TDao>();
            exchangeTask = lifetimeScope.Resolve<TTask>();
            if (mgLogger != null) log = mgLogger.CreateLog();
        }

        public virtual void Do()
        {
            var exchangeDtos = this.GetSyncDatas();
            DoAction(exchangeDtos);
        }

        protected virtual void DoAction(List<TDto> exchangeDtos)
        {
            if (exchangeDtos == null || exchangeDtos.Count == 0)
            {
                return;
            }
            ThreadPool.SetMaxThreads(MaxThreaderCount, MaxThreaderCount);
            do_totalThreadNumber = exchangeDtos.Count;

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            foreach (var dto in exchangeDtos)
            {
                //区分是否启用线程池
                if (useThreadPoolFlag)
                {
                    ThreadPool.QueueUserWorkItem(new WaitCallback(DoAction), dto);
                }
                else
                {
                    DoAction(dto);
                }
            }

            // 等待线程池执行完。
            if (useThreadPoolFlag)
            {
                threadEndEvent.WaitOne();
            }

            stopwatch.Stop();
            Debug.WriteLine("数据同步完成++++++++++++++++++++++++++++++++++++");
            Debug.WriteLine($"用时:{stopwatch.ElapsedMilliseconds}");
        }

        protected virtual List<TDto> GetSyncDatas()
        {
            return exchangeDao.GetSyncDatas<TDto>(null);
        }

        protected virtual void DoAction(object obj)
        {
            try
            {
                var param = obj as TDto;
                if (param == null)
                {
                    log.Error($"ExchangeTaskManager基类报错 ：param is null");
                    return;
                }

                exchangeTask.Do(param);
                // 测试用休眠
                //Thread.Sleep(1000);
            }
            catch (Exception exception)
            {
                log.Error(exception.Message + "\n" + exception.StackTrace);
            }
            finally
            {
                if (useThreadPoolFlag)
                {
                    doAction_checkThreadPoolIsEnd();
                }
            }
        }
        protected void doAction_checkThreadPoolIsEnd()
        {
            log.Information($"----------线程池任务数：{do_totalThreadNumber}------------");
            // 全局变量未同步数据减1
            //do_totalThreadNumber = do_totalThreadNumber - 1;
            do_totalThreadNumber--;
            if (do_totalThreadNumber <= 0)
            {
                log.Information($"----------跳出线程池------------");
                threadEndEvent.Set();
            }
        }
    }
}
